#include "commtraff_message_handler.h"
#include "commtraff_hilog.h"

#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <stddef.h>
#include <errno.h>


typedef struct {
    AsyncMessage *msg;
    ListNode node;
} AsyncMessageNode;



static void FreeAsyncMsg(AsyncMessage *msg)
{
    if (msg->FreeMessage) {
        msg->FreeMessage(msg);
    } else {
        free(msg);
    }
}

AsyncMessage *MallocAsyncMessage(void)
{
    AsyncMessage *msg = (AsyncMessage *)calloc(1, sizeof(AsyncMessage));
    if (!msg) {
        LOGE("MallocAsyncMessage: failed to allocate %zu bytes: %s (errno=%d)\n", sizeof(AsyncMessage), strerror(errno), errno);
        return NULL;
    }
    memset(msg, 0, sizeof(AsyncMessage));
    return msg;
}

void FreeAsyncMessage(AsyncMessage *msg)
{
    if (msg != NULL) {
        FreeAsyncMsg(msg);
    }
}

static void *LooperTask(void *arg)
{
    AsyncLooper *looper = (AsyncLooper *)arg;
    AsyncLooperContext *ctx = looper->context;

    while (!ctx->stop) {
        pthread_mutex_lock(&ctx->lock);

        if (IsListEmpty(&ctx->msgHead)) {
            pthread_cond_wait(&ctx->cond, &ctx->lock);
            pthread_mutex_unlock(&ctx->lock);
            continue;
        }

        ListNode *item = ctx->msgHead.next;
        AsyncMessageNode *node = (AsyncMessageNode *)((char *)item - offsetof(AsyncMessageNode, node));
        AsyncMessage *msg = node->msg;

        ListDelete(item);
        pthread_mutex_unlock(&ctx->lock);

        if (msg->HandleMessage) {
            msg->HandleMessage(msg);
        }

        FreeAsyncMsg(msg);
        free(node);
    }

    pthread_mutex_destroy(&ctx->lock);
    pthread_cond_destroy(&ctx->cond);
    free(ctx);
    free(looper);

    return NULL;
}

static void PostMessage(const AsyncLooper *looper, AsyncMessage *msg)
{
    if (looper == NULL) {
        LOGE("PostMessage: looper parameter is NULL\n");
        if (msg) {
            FreeAsyncMsg(msg);
        }
        return;
    }
    
    if (msg == NULL) {
        LOGE("PostMessage: message parameter is NULL\n");
        return;
    }
    
    AsyncLooperContext *ctx = looper->context;
    if (ctx == NULL) {
        LOGE("PostMessage: looper context is NULL\n");
        FreeAsyncMsg(msg);
        return;
    }

    pthread_mutex_lock(&ctx->lock);

    if (ctx->stop) {
        pthread_mutex_unlock(&ctx->lock);
        FreeAsyncMsg(msg);
        LOGE("PostMessage: looper '%s' is stopped, cannot post message\n", ctx->name);
        return;
    }

    AsyncMessageNode *newNode = (AsyncMessageNode *)malloc(sizeof(AsyncMessageNode));
    if (!newNode) {
        pthread_mutex_unlock(&ctx->lock);
        FreeAsyncMsg(msg);
        LOGE("PostMessage: failed to allocate %zu bytes for AsyncMessageNode in looper '%s': %s (errno=%d)\n", 
             sizeof(AsyncMessageNode), ctx->name, strerror(errno), errno);
        return;
    }
    ListInit(&newNode->node);
    newNode->msg = msg;
    ListTailInsert(&ctx->msgHead, &newNode->node);

    pthread_cond_signal(&ctx->cond);
    pthread_mutex_unlock(&ctx->lock);
}

AsyncLooper *CreateAsyncLooper(const char *name)
{
    static uint32_t g_looperCnt = 0;
    
    if (name == NULL) {
        LOGE("CreateAsyncLooper: name parameter is NULL\n");
        return NULL;
    }
    
    if (g_looperCnt >= MAX_LOOPER_CNT) {
        LOGE("CreateAsyncLooper: maximum number of loopers (%d) reached, cannot create '%s'\n", MAX_LOOPER_CNT, name);
        return NULL;
    }

    AsyncLooper *looper = (AsyncLooper *)malloc(sizeof(AsyncLooper));
    if (!looper) {
        LOGE("CreateAsyncLooper: failed to allocate %zu bytes for AsyncLooper '%s': %s (errno=%d)\n", 
             sizeof(AsyncLooper), name, strerror(errno), errno);
        return NULL;
    }

    AsyncLooperContext *ctx = (AsyncLooperContext *)malloc(sizeof(AsyncLooperContext));
    if (!ctx) {
        free(looper);
        LOGE("CreateAsyncLooper: failed to allocate %zu bytes for AsyncLooperContext '%s': %s (errno=%d)\n", 
             sizeof(AsyncLooperContext), name, strerror(errno), errno);
        return NULL;
    }

    strncpy(ctx->name, name, sizeof(ctx->name) - 1);
    ctx->name[sizeof(ctx->name) - 1] = '\0';
    ctx->stop = 0;
    ListInit(&ctx->msgHead);

    pthread_mutex_init(&ctx->lock, NULL);
    pthread_cond_init(&ctx->cond, NULL);

    looper->context = ctx;
    looper->PostMessage = PostMessage;

    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    if (pthread_create(&ctx->thread, &attr, LooperTask, looper) != 0) {
        LOGE("Failed to create thread\n");
        pthread_mutex_destroy(&ctx->lock);
        pthread_cond_destroy(&ctx->cond);
        free(ctx);
        free(looper);
        return NULL;
    }

    pthread_attr_destroy(&attr);
    g_looperCnt++;

    return looper;
}

void DestroyAsyncLooper(AsyncLooper *looper)
{
    if (!looper) {
        LOGE("DestroyAsyncLooper: looper parameter is NULL\n");
        return;
    }
    
    if (!looper->context) {
        LOGE("DestroyAsyncLooper: looper context is NULL\n");
        return;
    }

    AsyncLooperContext *ctx = looper->context;
    ctx->stop = 1;

    pthread_cond_signal(&ctx->cond);

    while (!IsListEmpty(&ctx->msgHead)) {
        ListNode *item = ctx->msgHead.next;
        AsyncMessageNode *node = (AsyncMessageNode *)((char *)item - offsetof(AsyncMessageNode, node));
        ListDelete(item);
        FreeAsyncMsg(node->msg);
        free(node);
    }
    return;
}
